package com.tbit.uqbike.protocol.AnalyzeImpl;

import com.tbit.uqbike.TerGatewayMain;
import com.tbit.uqbike.protocol.ABaseHandleObj;
import com.tbit.uqbike.protocol.ATerPkg;
import com.tbit.uqbike.tergateway.data.TerGatewayData;
import com.tbit.uqbike.tergateway.entity.AConnInfo;
import com.tbit.uqbike.tergateway.entity.ConnInfoTurn;
import com.tbit.uqbike.util.CharsetName;
import com.tbit.uqbike.util.ProtocolUtil;
import com.tbit.uqbike.util.StringUtil;
import io.netty.buffer.ByteBuf;

import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by MyWin on 2018/6/26 0026.
 * 分包转发透传协议
 * 0xEEEE 开头
 * 1 byte 命令字
 * 1 byte 保留
 * 4 byte 数据体长度 表示接下来数据体有多长
 * n byte 数据体（数据体里面的数据采用LV的形式）
 * 2 byte crc 从命令字开始一直到数据体最后一个字节
 * <p>
 * 命令字:0x1(数据转发)
 * 数据体依次数据如下：
 * 连接ID：1 byte长度  + n byte
 * +
 * 数据包：4 byte长度 + n byte
 */
public class TurnDeEnCoder extends AProtocol {
    /// <summary>
    /// 每个包EE EE 开头
    /// </summary>
    public static final byte[] PRO_HEAD = new byte[]{(byte) 0xee, (byte) 0xee};
    public static final String protocolName = "TBIT_TURN";
    public static final int MIN_PKG = 2 + 1 + 1 + 4 + 2;// 最小包大小
    public static final int DATA_INDEX = MIN_PKG - 2;

    @Override
    public String getProtocolName() {
        return protocolName;
    }

    @Override
    public List<ATerPkg> analyzeTerPkg(AConnInfo conn, ByteBuf in) {
        List<ATerPkg> list = new LinkedList<>();
        int readIndex = in.readerIndex();
        long pkgLen = 0;
        while (in.readableBytes() >= MIN_PKG) {
            readIndex = in.readerIndex();
            if (in.getByte(readIndex) == PRO_HEAD[0] && in.getByte(readIndex + 1) == PRO_HEAD[1]) {
                readIndex += 2;
                readIndex += 2;// 跳过命令字和保留字
                pkgLen = in.getUnsignedInt(readIndex);
                readIndex += 4;
                if (in.readableBytes() >= pkgLen + MIN_PKG) {
                    int calCrc = ProtocolUtil.GetCrcByteArray(in, readIndex - 6, (int) pkgLen + 6);
                    int pkgCrc = in.getUnsignedShort(readIndex + (int) pkgLen);
                    if (calCrc == pkgCrc) {
                        // 完整报文 读取前面的头
                        in.skipBytes(2 + 1 + 1 + 4);
                        List<ATerPkg> pkgList = analyzePkg(conn, in);
                        // 解析完数据以后 读取后面的2个字节校验
                        in.skipBytes(2);
                        if (null != pkgList && !pkgList.isEmpty()) {
                            list.addAll(pkgList);
                        }
                    } else {
                        in.skipBytes(1);
                    }
                }
            } else {
                in.skipBytes(1);
            }
        }
        return list;
    }

    private List<ATerPkg> analyzePkg(AConnInfo conn, ByteBuf in) {
        // 再自动识别一下协议，解析出对象
        // 直接取出数据
        if (in.readableBytes() > MIN_PKG + 5) {
            int index = DATA_INDEX;
            try {
                int len = in.readUnsignedByte();
                byte[] tempBs = new byte[len];
                in.readBytes(tempBs);
                String connId = new String(tempBs, 0, tempBs.length, CharsetName.US_ASCII);
                len = in.readInt();
                return analyzeProtocol(conn, connId, len, in);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    private List<ATerPkg> analyzeProtocol(AConnInfo conn, String connId, int len, ByteBuf in) {
        // 根据连接id获取或者创建连接对象，然后根据连接对象拿到连接协议，然后使用协议的解析解析对象
        AProtocol protocol = null;
        AConnInfo terConn = null;
        String nConnId = String.format("%s.%s", conn.connId, connId);
        terConn = TerGatewayData.GetConnect(nConnId);
        if (null == terConn) {
            terConn = new ConnInfoTurn(connId, conn.connId);
            TerGatewayData.AddConnect(terConn);
        }
        String proName = terConn.proName;
        if (StringUtil.IsNullOrEmpty(proName)) {
            protocol = TerGatewayMain.autoProtocol.autoProtocol(in);
        } else {
            protocol = AAutoProtocol.getProtocol(proName);
        }
        if (protocol != null) {
            terConn.proName = protocol.getProtocolName();
            return protocol.analyzeTerPkg(terConn, in);
        } else {
            return null;
        }
    }

    @Override
    public ByteBuf builtRemoteControlPkg(AConnInfo conn, ABaseHandleObj aBaseHandleObj) {
        return null;
    }
}
